#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

int main()
{
	int fd = open("/dev/video2",O_RDWR);
	if(fd < 0){
		perror("打开设备失败");
		return -1;
	}

	struct v4l2_format vfmt;

	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	vfmt.fmt.pix.width = 1280;
	vfmt.fmt.pix.height = 720;
	vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;

	int ret = ioctl(fd,VIDIOC_S_FMT,&vfmt);
	if(ret < 0){
		perror("设置格式失败\r\n");
	}

	//申请内核空间
	struct v4l2_requestbuffers reqbuffer;
	reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuffer.count = 4;
	reqbuffer.memory = V4L2_MEMORY_MMAP;
	
	ret = ioctl(fd,VIDIOC_REQBUFS,&reqbuffer);
	if(ret < 0){
		perror("申请空间失败\r\n");
	}

	unsigned char *mptr[4];
	unsigned int size[4];
	struct v4l2_buffer mapbuffer;
	mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	
	for(int i = 0 ; i < 4 ; i++){
		mapbuffer.index = i;
		ret = ioctl(fd,VIDIOC_QUERYBUF,&mapbuffer);
		if(ret < 0){
			printf("查阅内核空间失败\r\n");
		} 
		mptr[i] =(unsigned char *)mmap(NULL,mapbuffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,mapbuffer.m.offset);
		size[i] = mapbuffer.length;
		ret = ioctl(fd,VIDIOC_QBUF,&mapbuffer);
		if(ret < 0){
			perror("放回失败\r\n");
		}
	}

	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd,VIDIOC_STREAMON,&type);
	if(ret < 0){
		printf("开启失败\r\n");
	}

	struct v4l2_buffer readbuffer;
	readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd,VIDIOC_DQBUF,&readbuffer);
	if(ret < 0){
		perror("读取数据失败\r\n");
	}
	FILE *file = fopen("my.jpg","w+");
	fwrite(mptr[readbuffer.index],readbuffer.length,1,file);
	fclose(file);

	ret = ioctl(fd,VIDIOC_QBUF,&readbuffer);
	if(ret){
		perror("队列放回失败\r\n");
	}

	ret = ioctl(fd,VIDIOC_STREAMOFF,&type);

	for(int i = 0; i < 4; i++)munmap(mptr[i],size[i]);

	close(fd);
	return 0;
}